#!/bin/bash

# ══════════════════════════════════════════════════════
#  Live System Monitor Dashboard
#  Exit with Ctrl+C
# ══════════════════════════════════════════════════════

# Colors
RED='\033[0;31m'
BRIGHT_RED='\033[1;31m'
GREEN='\033[0;32m'
BRIGHT_GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BRIGHT_BLUE='\033[1;34m'
CYAN='\033[0;36m'
BRIGHT_CYAN='\033[1;36m'
MAGENTA='\033[0;35m'
BRIGHT_MAGENTA='\033[1;35m'
WHITE='\033[1;37m'
DIM='\033[2m'
RESET='\033[0m'

REFRESH=2  # seconds between updates

cleanup() {
    tput rmcup
    tput cnorm
    clear
    echo -e "${CYAN}System monitor closed.${RESET}"
    exit 0
}
trap cleanup SIGINT SIGTERM

# ─────────────────────────────────────────
# Draw a bar graph  e.g.  [████████░░░░] 65%
# ─────────────────────────────────────────
draw_bar() {
    local value=$1      # 0-100
    local width=${2:-30}
    local filled=$(( value * width / 100 ))
    local empty=$(( width - filled ))

    # Color based on value
    local color
    if   (( value >= 90 )); then color=$BRIGHT_RED
    elif (( value >= 75 )); then color=$YELLOW
    elif (( value >= 50 )); then color=$BRIGHT_CYAN
    else                         color=$BRIGHT_GREEN
    fi

    echo -ne "${DIM}[${RESET}${color}"
    for (( i=0; i<filled; i++ )); do echo -ne "█"; done
    echo -ne "${DIM}"
    for (( i=0; i<empty;  i++ )); do echo -ne "░"; done
    echo -ne "]${RESET}"
}

# ─────────────────────────────────────────
# Color a percentage value
# ─────────────────────────────────────────
color_pct() {
    local val=$1
    if   (( val >= 90 )); then echo -ne "${BRIGHT_RED}${val}%${RESET}"
    elif (( val >= 75 )); then echo -ne "${YELLOW}${val}%${RESET}"
    elif (( val >= 50 )); then echo -ne "${BRIGHT_CYAN}${val}%${RESET}"
    else                       echo -ne "${BRIGHT_GREEN}${val}%${RESET}"
    fi
}

# ─────────────────────────────────────────
# Convert bytes to human readable
# ─────────────────────────────────────────
human_bytes() {
    local bytes=$1
    if   (( bytes >= 1073741824 )); then printf "%.1f GB" "$(echo "scale=1; $bytes/1073741824" | bc)"
    elif (( bytes >= 1048576    )); then printf "%.1f MB" "$(echo "scale=1; $bytes/1048576"    | bc)"
    elif (( bytes >= 1024       )); then printf "%.1f KB" "$(echo "scale=1; $bytes/1024"       | bc)"
    else                                printf "%d B"  "$bytes"
    fi
}

# ─────────────────────────────────────────
# Get CPU usage %
# ─────────────────────────────────────────
get_cpu() {
    # Read /proc/stat twice with a short gap for accurate usage
    local line1 line2
    line1=$(grep '^cpu ' /proc/stat)
    sleep 0.3
    line2=$(grep '^cpu ' /proc/stat)

    local u1 n1 s1 i1 w1 u2 n2 s2 i2 w2
    read -r _ u1 n1 s1 i1 w1 _ _ _ _ <<< "$line1"
    read -r _ u2 n2 s2 i2 w2 _ _ _ _ <<< "$line2"

    local idle1=$(( i1 + w1 ))
    local idle2=$(( i2 + w2 ))
    local total1=$(( u1 + n1 + s1 + i1 + w1 ))
    local total2=$(( u2 + n2 + s2 + i2 + w2 ))
    local diff_idle=$(( idle2  - idle1  ))
    local diff_total=$(( total2 - total1 ))
    local diff_used=$(( diff_total - diff_idle ))

    if (( diff_total == 0 )); then echo 0
    else echo $(( diff_used * 100 / diff_total ))
    fi
}

# ─────────────────────────────────────────
# Get per-core CPU usage
# ─────────────────────────────────────────
get_cores() {
    local cores_before cores_after
    cores_before=$(grep '^cpu[0-9]' /proc/stat)
    sleep 0.1
    cores_after=$(grep '^cpu[0-9]' /proc/stat)

    local result=()
    local count=0
    while IFS= read -r line; do
        local name u n s i w
        read -r name u n s i w _ _ _ _ <<< "$line"
        local after_line
        after_line=$(echo "$cores_after" | grep "^$name ")
        local au an as_ ai aw
        read -r _ au an as_ ai aw _ _ _ _ <<< "$after_line"

        local idle1=$(( i  + w  ))
        local idle2=$(( ai + aw ))
        local total1=$(( u  + n  + s  + i  + w  ))
        local total2=$(( au + an + as_ + ai + aw ))
        local diff_idle=$(( idle2  - idle1  ))
        local diff_total=$(( total2 - total1 ))
        local diff_used=$(( diff_total - diff_idle ))
        local pct=0
        (( diff_total > 0 )) && pct=$(( diff_used * 100 / diff_total ))
        result+=("$pct")
        (( count++ ))
        (( count >= 8 )) && break   # cap at 8 cores shown
    done <<< "$cores_before"

    echo "${result[@]}"
}

# ─────────────────────────────────────────
# Network stats (bytes in/out since boot)
# ─────────────────────────────────────────
NET_IFACE=""
get_net_iface() {
    # Pick first non-loopback interface that has traffic
    NET_IFACE=$(ip -o link show | awk -F': ' '{print $2}' | grep -v lo | head -1)
    [ -z "$NET_IFACE" ] && NET_IFACE="eth0"
}

get_net_bytes() {
    local iface=$1
    local rx tx
    rx=$(cat /sys/class/net/${iface}/statistics/rx_bytes 2>/dev/null || echo 0)
    tx=$(cat /sys/class/net/${iface}/statistics/tx_bytes 2>/dev/null || echo 0)
    echo "$rx $tx"
}

# ─────────────────────────────────────────
# Setup
# ─────────────────────────────────────────
tput smcup
tput civis
get_net_iface

# Initial network reading
read -r NET_RX_PREV NET_TX_PREV <<< "$(get_net_bytes "$NET_IFACE")"

# ─────────────────────────────────────────
# Main loop
# ─────────────────────────────────────────
while true; do
    COLS=$(tput cols)
    LINES=$(tput lines)

    # ── Gather all stats ──

    # CPU
    CPU_PCT=$(get_cpu)

    # Per-core
    CORE_PCTS=($(get_cores))
    NUM_CORES=${#CORE_PCTS[@]}

    # CPU info
    CPU_MODEL=$(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
    CPU_MHZ=$(grep 'cpu MHz' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs | cut -d. -f1)
    CPU_TEMP=""
    if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
        local_temp=$(cat /sys/class/thermal/thermal_zone0/temp)
        CPU_TEMP="$(( local_temp / 1000 ))°C"
    fi

    # RAM
    RAM_TOTAL=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    RAM_FREE=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
    RAM_USED=$(( RAM_TOTAL - RAM_FREE ))
    RAM_PCT=$(( RAM_USED * 100 / RAM_TOTAL ))
    RAM_USED_H=$(human_bytes $(( RAM_USED * 1024 )))
    RAM_TOTAL_H=$(human_bytes $(( RAM_TOTAL * 1024 )))

    # Swap
    SWAP_TOTAL=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
    SWAP_FREE=$(grep SwapFree  /proc/meminfo | awk '{print $2}')
    SWAP_USED=$(( SWAP_TOTAL - SWAP_FREE ))
    SWAP_PCT=0
    (( SWAP_TOTAL > 0 )) && SWAP_PCT=$(( SWAP_USED * 100 / SWAP_TOTAL ))
    SWAP_USED_H=$(human_bytes $(( SWAP_USED * 1024 )))
    SWAP_TOTAL_H=$(human_bytes $(( SWAP_TOTAL * 1024 )))

    # Disk
    DISK_INFO=$(df -h / | tail -1)
    DISK_USED=$(echo "$DISK_INFO" | awk '{print $3}')
    DISK_TOTAL=$(echo "$DISK_INFO" | awk '{print $2}')
    DISK_PCT=$(echo "$DISK_INFO" | awk '{print $5}' | tr -d '%')
    DISK_AVAIL=$(echo "$DISK_INFO" | awk '{print $4}')

    # Extra disks
    HOME_INFO=$(df -h /home 2>/dev/null | tail -1)
    HOME_PCT=$(echo "$HOME_INFO" | awk '{print $5}' | tr -d '%')
    HOME_USED=$(echo "$HOME_INFO" | awk '{print $3}')
    HOME_TOTAL=$(echo "$HOME_INFO" | awk '{print $2}')

    # Network speed (bytes since last loop)
    read -r NET_RX_NOW NET_TX_NOW <<< "$(get_net_bytes "$NET_IFACE")"
    NET_RX_SPEED=$(( (NET_RX_NOW - NET_RX_PREV) / REFRESH ))
    NET_TX_SPEED=$(( (NET_TX_NOW - NET_TX_PREV) / REFRESH ))
    NET_RX_PREV=$NET_RX_NOW
    NET_TX_PREV=$NET_TX_NOW
    NET_RX_H=$(human_bytes $NET_RX_SPEED)
    NET_TX_H=$(human_bytes $NET_TX_SPEED)
    NET_RX_TOTAL_H=$(human_bytes $NET_RX_NOW)
    NET_TX_TOTAL_H=$(human_bytes $NET_TX_NOW)

    # System info
    HOSTNAME=$(hostname)
    KERNEL=$(uname -r)
    UPTIME=$(uptime -p 2>/dev/null | sed 's/up //' || uptime | sed 's/.*up //' | cut -d, -f1)
    LOAD=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
    PROCS=$(ps aux | wc -l)
    TIME_NOW=$(date '+%H:%M:%S')
    DATE_NOW=$(date '+%A %d %b %Y')

    # ── Draw dashboard ──
    clear

    # Title bar
    echo -e "${BRIGHT_CYAN}╔$(printf '═%.0s' $(seq 1 $((COLS-2))))╗${RESET}"
    printf "${BRIGHT_CYAN}║${RESET}${WHITE}  ⚡ SYSTEM MONITOR  ${DIM}│${RESET}  ${CYAN}%-20s${RESET}  ${DIM}│${RESET}  ${DIM}%s  %s${RESET}"  "$HOSTNAME"  "$DATE_NOW"  "$TIME_NOW"
    printf "%$((COLS - 62))s"
    echo -e "${BRIGHT_CYAN}║${RESET}"
    echo -e "${BRIGHT_CYAN}╚$(printf '═%.0s' $(seq 1 $((COLS-2))))╝${RESET}"
    echo ""

    # System info row
    printf "  ${DIM}Kernel:${RESET} ${WHITE}%-30s${RESET}  ${DIM}Uptime:${RESET} ${WHITE}%-25s${RESET}  ${DIM}Load avg:${RESET} ${WHITE}%s${RESET}\n" \
        "$KERNEL" "$UPTIME" "$LOAD"
    printf "  ${DIM}CPU:${RESET}    ${WHITE}%-58s${RESET}  ${DIM}Processes:${RESET} ${WHITE}%s${RESET}\n" \
        "${CPU_MODEL:0:55}" "$PROCS"
    echo ""

    # ── CPU ──
    echo -e "  ${BRIGHT_YELLOW:-$YELLOW}┌─ 💻 CPU $(printf '─%.0s' $(seq 1 $((COLS-14))))${RESET}"
    echo ""

    printf "  ${WHITE}Overall:${RESET}  "
    draw_bar "$CPU_PCT" 40
    printf "  "
    color_pct "$CPU_PCT"
    [ -n "$CPU_TEMP" ] && printf "   ${DIM}Temp:${RESET} ${WHITE}%s${RESET}" "$CPU_TEMP"
    printf "   ${DIM}%s MHz${RESET}\n" "$CPU_MHZ"
    echo ""

    # Per-core bars (up to 8, 2 rows of 4)
    if (( NUM_CORES > 0 )); then
        printf "  "
        for (( c=0; c<NUM_CORES && c<4; c++ )); do
            printf "${DIM}Core%-2d${RESET} " "$c"
            draw_bar "${CORE_PCTS[$c]}" 10
            printf " "
            color_pct "${CORE_PCTS[$c]}"
            printf "   "
        done
        echo ""
        if (( NUM_CORES > 4 )); then
            printf "  "
            for (( c=4; c<NUM_CORES && c<8; c++ )); do
                printf "${DIM}Core%-2d${RESET} " "$c"
                draw_bar "${CORE_PCTS[$c]}" 10
                printf " "
                color_pct "${CORE_PCTS[$c]}"
                printf "   "
            done
            echo ""
        fi
    fi
    echo ""

    # ── Memory ──
    echo -e "  ${BRIGHT_CYAN}┌─ 🧠 MEMORY $(printf '─%.0s' $(seq 1 $((COLS-16))))${RESET}"
    echo ""
    printf "  ${WHITE}RAM:   ${RESET}"
    draw_bar "$RAM_PCT" 40
    printf "  "
    color_pct "$RAM_PCT"
    printf "  ${DIM}%s / %s${RESET}\n" "$RAM_USED_H" "$RAM_TOTAL_H"

    printf "  ${WHITE}Swap:  ${RESET}"
    draw_bar "$SWAP_PCT" 40
    printf "  "
    color_pct "$SWAP_PCT"
    printf "  ${DIM}%s / %s${RESET}\n" "$SWAP_USED_H" "$SWAP_TOTAL_H"
    echo ""

    # ── Disk ──
    echo -e "  ${BRIGHT_GREEN}┌─ 💾 DISK $(printf '─%.0s' $(seq 1 $((COLS-14))))${RESET}"
    echo ""
    printf "  ${WHITE}/      ${RESET}"
    draw_bar "$DISK_PCT" 40
    printf "  "
    color_pct "$DISK_PCT"
    printf "  ${DIM}%s used of %s  (%s free)${RESET}\n" "$DISK_USED" "$DISK_TOTAL" "$DISK_AVAIL"

    if [ -n "$HOME_PCT" ] && [ "$HOME_PCT" != "$DISK_PCT" ]; then
        printf "  ${WHITE}/home  ${RESET}"
        draw_bar "$HOME_PCT" 40
        printf "  "
        color_pct "$HOME_PCT"
        printf "  ${DIM}%s used of %s${RESET}\n" "$HOME_USED" "$HOME_TOTAL"
    fi
    echo ""

    # ── Network ──
    echo -e "  ${BRIGHT_MAGENTA}┌─ 🌐 NETWORK ─ ${WHITE}${NET_IFACE}$(printf '─%.0s' $(seq 1 $((COLS-18-${#NET_IFACE}))))${RESET}"
    echo ""
    printf "  ${GREEN}▼ Download:${RESET}  ${WHITE}%-12s/s${RESET}   ${DIM}Total received:${RESET} ${WHITE}%s${RESET}\n" \
        "$NET_RX_H" "$NET_RX_TOTAL_H"
    printf "  ${YELLOW}▲ Upload:  ${RESET}  ${WHITE}%-12s/s${RESET}   ${DIM}Total sent:    ${RESET} ${WHITE}%s${RESET}\n" \
        "$NET_TX_H" "$NET_TX_TOTAL_H"
    echo ""

    # ── Top processes ──
    echo -e "  ${BRIGHT_RED}┌─ 🔥 TOP PROCESSES $(printf '─%.0s' $(seq 1 $((COLS-23))))${RESET}"
    echo ""
    printf "  ${DIM}%-6s  %-20s  %6s  %6s  %s${RESET}\n" "PID" "NAME" "CPU%" "MEM%" "COMMAND"
    echo -e "  ${DIM}$(printf '─%.0s' $(seq 1 $((COLS-4))))${RESET}"

    ps aux --sort=-%cpu | awk 'NR>1 {printf "  \033[1;37m%-6s\033[0m  \033[0;36m%-20s\033[0m  \033[1;33m%6s\033[0m  \033[1;35m%6s\033[0m  \033[2m%s\033[0m\n", $2, $11, $3, $4, substr($0, index($0,$11))}' | head -7

    echo ""

    # Footer
    echo -e "${DIM}  Refreshing every ${REFRESH}s  •  Ctrl+C to exit  •  $(date '+%H:%M:%S')${RESET}"

    sleep $REFRESH
done
